sysconfig.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2012 The Python Software Foundation.
  4. # See LICENSE.txt and CONTRIBUTORS.txt.
  5. #
  6. """Access to Python's configuration information."""
  7. import codecs
  8. import os
  9. import re
  10. import sys
  11. from os.path import pardir, realpath
  12. try:
  13. import configparser
  14. except ImportError:
  15. import ConfigParser as configparser
  16. __all__ = [
  17. 'get_config_h_filename',
  18. 'get_config_var',
  19. 'get_config_vars',
  20. 'get_makefile_filename',
  21. 'get_path',
  22. 'get_path_names',
  23. 'get_paths',
  24. 'get_platform',
  25. 'get_python_version',
  26. 'get_scheme_names',
  27. 'parse_config_h',
  28. ]
  29. def _safe_realpath(path):
  30. try:
  31. return realpath(path)
  32. except OSError:
  33. return path
  34. if sys.executable:
  35. _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
  36. else:
  37. # sys.executable can be empty if argv[0] has been changed and Python is
  38. # unable to retrieve the real program name
  39. _PROJECT_BASE = _safe_realpath(os.getcwd())
  40. if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower():
  41. _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir))
  42. # PC/VS7.1
  43. if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower():
  44. _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
  45. # PC/AMD64
  46. if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower():
  47. _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
  48. def is_python_build():
  49. for fn in ("Setup.dist", "Setup.local"):
  50. if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)):
  51. return True
  52. return False
  53. _PYTHON_BUILD = is_python_build()
  54. _cfg_read = False
  55. def _ensure_cfg_read():
  56. global _cfg_read
  57. if not _cfg_read:
  58. from ..resources import finder
  59. backport_package = __name__.rsplit('.', 1)[0]
  60. _finder = finder(backport_package)
  61. _cfgfile = _finder.find('sysconfig.cfg')
  62. assert _cfgfile, 'sysconfig.cfg exists'
  63. with _cfgfile.as_stream() as s:
  64. _SCHEMES.readfp(s)
  65. if _PYTHON_BUILD:
  66. for scheme in ('posix_prefix', 'posix_home'):
  67. _SCHEMES.set(scheme, 'include', '{srcdir}/Include')
  68. _SCHEMES.set(scheme, 'platinclude', '{projectbase}/.')
  69. _cfg_read = True
  70. _SCHEMES = configparser.RawConfigParser()
  71. _VAR_REPL = re.compile(r'\{([^{]*?)\}')
  72. def _expand_globals(config):
  73. _ensure_cfg_read()
  74. if config.has_section('globals'):
  75. globals = config.items('globals')
  76. else:
  77. globals = tuple()
  78. sections = config.sections()
  79. for section in sections:
  80. if section == 'globals':
  81. continue
  82. for option, value in globals:
  83. if config.has_option(section, option):
  84. continue
  85. config.set(section, option, value)
  86. config.remove_section('globals')
  87. # now expanding local variables defined in the cfg file
  88. #
  89. for section in config.sections():
  90. variables = dict(config.items(section))
  91. def _replacer(matchobj):
  92. name = matchobj.group(1)
  93. if name in variables:
  94. return variables[name]
  95. return matchobj.group(0)
  96. for option, value in config.items(section):
  97. config.set(section, option, _VAR_REPL.sub(_replacer, value))
  98. #_expand_globals(_SCHEMES)
  99. _PY_VERSION = '%s.%s.%s' % sys.version_info[:3]
  100. _PY_VERSION_SHORT = '%s.%s' % sys.version_info[:2]
  101. _PY_VERSION_SHORT_NO_DOT = '%s%s' % sys.version_info[:2]
  102. _PREFIX = os.path.normpath(sys.prefix)
  103. _EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
  104. _CONFIG_VARS = None
  105. _USER_BASE = None
  106. def _subst_vars(path, local_vars):
  107. """In the string `path`, replace tokens like {some.thing} with the
  108. corresponding value from the map `local_vars`.
  109. If there is no corresponding value, leave the token unchanged.
  110. """
  111. def _replacer(matchobj):
  112. name = matchobj.group(1)
  113. if name in local_vars:
  114. return local_vars[name]
  115. elif name in os.environ:
  116. return os.environ[name]
  117. return matchobj.group(0)
  118. return _VAR_REPL.sub(_replacer, path)
  119. def _extend_dict(target_dict, other_dict):
  120. target_keys = target_dict.keys()
  121. for key, value in other_dict.items():
  122. if key in target_keys:
  123. continue
  124. target_dict[key] = value
  125. def _expand_vars(scheme, vars):
  126. res = {}
  127. if vars is None:
  128. vars = {}
  129. _extend_dict(vars, get_config_vars())
  130. for key, value in _SCHEMES.items(scheme):
  131. if os.name in ('posix', 'nt'):
  132. value = os.path.expanduser(value)
  133. res[key] = os.path.normpath(_subst_vars(value, vars))
  134. return res
  135. def format_value(value, vars):
  136. def _replacer(matchobj):
  137. name = matchobj.group(1)
  138. if name in vars:
  139. return vars[name]
  140. return matchobj.group(0)
  141. return _VAR_REPL.sub(_replacer, value)
  142. def _get_default_scheme():
  143. if os.name == 'posix':
  144. # the default scheme for posix is posix_prefix
  145. return 'posix_prefix'
  146. return os.name
  147. def _getuserbase():
  148. env_base = os.environ.get("PYTHONUSERBASE", None)
  149. def joinuser(*args):
  150. return os.path.expanduser(os.path.join(*args))
  151. # what about 'os2emx', 'riscos' ?
  152. if os.name == "nt":
  153. base = os.environ.get("APPDATA") or "~"
  154. if env_base:
  155. return env_base
  156. else:
  157. return joinuser(base, "Python")
  158. if sys.platform == "darwin":
  159. framework = get_config_var("PYTHONFRAMEWORK")
  160. if framework:
  161. if env_base:
  162. return env_base
  163. else:
  164. return joinuser("~", "Library", framework, "%d.%d" %
  165. sys.version_info[:2])
  166. if env_base:
  167. return env_base
  168. else:
  169. return joinuser("~", ".local")
  170. def _parse_makefile(filename, vars=None):
  171. """Parse a Makefile-style file.
  172. A dictionary containing name/value pairs is returned. If an
  173. optional dictionary is passed in as the second argument, it is
  174. used instead of a new dictionary.
  175. """
  176. # Regexes needed for parsing Makefile (and similar syntaxes,
  177. # like old-style Setup files).
  178. _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
  179. _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
  180. _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
  181. if vars is None:
  182. vars = {}
  183. done = {}
  184. notdone = {}
  185. with codecs.open(filename, encoding='utf-8', errors="surrogateescape") as f:
  186. lines = f.readlines()
  187. for line in lines:
  188. if line.startswith('#') or line.strip() == '':
  189. continue
  190. m = _variable_rx.match(line)
  191. if m:
  192. n, v = m.group(1, 2)
  193. v = v.strip()
  194. # `$$' is a literal `$' in make
  195. tmpv = v.replace('$$', '')
  196. if "$" in tmpv:
  197. notdone[n] = v
  198. else:
  199. try:
  200. v = int(v)
  201. except ValueError:
  202. # insert literal `$'
  203. done[n] = v.replace('$$', '$')
  204. else:
  205. done[n] = v
  206. # do variable interpolation here
  207. variables = list(notdone.keys())
  208. # Variables with a 'PY_' prefix in the makefile. These need to
  209. # be made available without that prefix through sysconfig.
  210. # Special care is needed to ensure that variable expansion works, even
  211. # if the expansion uses the name without a prefix.
  212. renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
  213. while len(variables) > 0:
  214. for name in tuple(variables):
  215. value = notdone[name]
  216. m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
  217. if m is not None:
  218. n = m.group(1)
  219. found = True
  220. if n in done:
  221. item = str(done[n])
  222. elif n in notdone:
  223. # get it on a subsequent round
  224. found = False
  225. elif n in os.environ:
  226. # do it like make: fall back to environment
  227. item = os.environ[n]
  228. elif n in renamed_variables:
  229. if (name.startswith('PY_') and
  230. name[3:] in renamed_variables):
  231. item = ""
  232. elif 'PY_' + n in notdone:
  233. found = False
  234. else:
  235. item = str(done['PY_' + n])
  236. else:
  237. done[n] = item = ""
  238. if found:
  239. after = value[m.end():]
  240. value = value[:m.start()] + item + after
  241. if "$" in after:
  242. notdone[name] = value
  243. else:
  244. try:
  245. value = int(value)
  246. except ValueError:
  247. done[name] = value.strip()
  248. else:
  249. done[name] = value
  250. variables.remove(name)
  251. if (name.startswith('PY_') and
  252. name[3:] in renamed_variables):
  253. name = name[3:]
  254. if name not in done:
  255. done[name] = value
  256. else:
  257. # bogus variable reference (e.g. "prefix=$/opt/python");
  258. # just drop it since we can't deal
  259. done[name] = value
  260. variables.remove(name)
  261. # strip spurious spaces
  262. for k, v in done.items():
  263. if isinstance(v, str):
  264. done[k] = v.strip()
  265. # save the results in the global dictionary
  266. vars.update(done)
  267. return vars
  268. def get_makefile_filename():
  269. """Return the path of the Makefile."""
  270. if _PYTHON_BUILD:
  271. return os.path.join(_PROJECT_BASE, "Makefile")
  272. if hasattr(sys, 'abiflags'):
  273. config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags)
  274. else:
  275. config_dir_name = 'config'
  276. return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
  277. def _init_posix(vars):
  278. """Initialize the module as appropriate for POSIX systems."""
  279. # load the installed Makefile:
  280. makefile = get_makefile_filename()
  281. try:
  282. _parse_makefile(makefile, vars)
  283. except IOError as e:
  284. msg = "invalid Python installation: unable to open %s" % makefile
  285. if hasattr(e, "strerror"):
  286. msg = msg + " (%s)" % e.strerror
  287. raise IOError(msg)
  288. # load the installed pyconfig.h:
  289. config_h = get_config_h_filename()
  290. try:
  291. with open(config_h) as f:
  292. parse_config_h(f, vars)
  293. except IOError as e:
  294. msg = "invalid Python installation: unable to open %s" % config_h
  295. if hasattr(e, "strerror"):
  296. msg = msg + " (%s)" % e.strerror
  297. raise IOError(msg)
  298. # On AIX, there are wrong paths to the linker scripts in the Makefile
  299. # -- these paths are relative to the Python source, but when installed
  300. # the scripts are in another directory.
  301. if _PYTHON_BUILD:
  302. vars['LDSHARED'] = vars['BLDSHARED']
  303. def _init_non_posix(vars):
  304. """Initialize the module as appropriate for NT"""
  305. # set basic install directories
  306. vars['LIBDEST'] = get_path('stdlib')
  307. vars['BINLIBDEST'] = get_path('platstdlib')
  308. vars['INCLUDEPY'] = get_path('include')
  309. vars['SO'] = '.pyd'
  310. vars['EXE'] = '.exe'
  311. vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
  312. vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
  313. #
  314. # public APIs
  315. #
  316. def parse_config_h(fp, vars=None):
  317. """Parse a config.h-style file.
  318. A dictionary containing name/value pairs is returned. If an
  319. optional dictionary is passed in as the second argument, it is
  320. used instead of a new dictionary.
  321. """
  322. if vars is None:
  323. vars = {}
  324. define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
  325. undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
  326. while True:
  327. line = fp.readline()
  328. if not line:
  329. break
  330. m = define_rx.match(line)
  331. if m:
  332. n, v = m.group(1, 2)
  333. try:
  334. v = int(v)
  335. except ValueError:
  336. pass
  337. vars[n] = v
  338. else:
  339. m = undef_rx.match(line)
  340. if m:
  341. vars[m.group(1)] = 0
  342. return vars
  343. def get_config_h_filename():
  344. """Return the path of pyconfig.h."""
  345. if _PYTHON_BUILD:
  346. if os.name == "nt":
  347. inc_dir = os.path.join(_PROJECT_BASE, "PC")
  348. else:
  349. inc_dir = _PROJECT_BASE
  350. else:
  351. inc_dir = get_path('platinclude')
  352. return os.path.join(inc_dir, 'pyconfig.h')
  353. def get_scheme_names():
  354. """Return a tuple containing the schemes names."""
  355. return tuple(sorted(_SCHEMES.sections()))
  356. def get_path_names():
  357. """Return a tuple containing the paths names."""
  358. # xxx see if we want a static list
  359. return _SCHEMES.options('posix_prefix')
  360. def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
  361. """Return a mapping containing an install scheme.
  362. ``scheme`` is the install scheme name. If not provided, it will
  363. return the default scheme for the current platform.
  364. """
  365. _ensure_cfg_read()
  366. if expand:
  367. return _expand_vars(scheme, vars)
  368. else:
  369. return dict(_SCHEMES.items(scheme))
  370. def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
  371. """Return a path corresponding to the scheme.
  372. ``scheme`` is the install scheme name.
  373. """
  374. return get_paths(scheme, vars, expand)[name]
  375. def get_config_vars(*args):
  376. """With no arguments, return a dictionary of all configuration
  377. variables relevant for the current platform.
  378. On Unix, this means every variable defined in Python's installed Makefile;
  379. On Windows and Mac OS it's a much smaller set.
  380. With arguments, return a list of values that result from looking up
  381. each argument in the configuration variable dictionary.
  382. """
  383. global _CONFIG_VARS
  384. if _CONFIG_VARS is None:
  385. _CONFIG_VARS = {}
  386. # Normalized versions of prefix and exec_prefix are handy to have;
  387. # in fact, these are the standard versions used most places in the
  388. # distutils2 module.
  389. _CONFIG_VARS['prefix'] = _PREFIX
  390. _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
  391. _CONFIG_VARS['py_version'] = _PY_VERSION
  392. _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
  393. _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2]
  394. _CONFIG_VARS['base'] = _PREFIX
  395. _CONFIG_VARS['platbase'] = _EXEC_PREFIX
  396. _CONFIG_VARS['projectbase'] = _PROJECT_BASE
  397. try:
  398. _CONFIG_VARS['abiflags'] = sys.abiflags
  399. except AttributeError:
  400. # sys.abiflags may not be defined on all platforms.
  401. _CONFIG_VARS['abiflags'] = ''
  402. if os.name in ('nt', 'os2'):
  403. _init_non_posix(_CONFIG_VARS)
  404. if os.name == 'posix':
  405. _init_posix(_CONFIG_VARS)
  406. # Setting 'userbase' is done below the call to the
  407. # init function to enable using 'get_config_var' in
  408. # the init-function.
  409. if sys.version >= '2.6':
  410. _CONFIG_VARS['userbase'] = _getuserbase()
  411. if 'srcdir' not in _CONFIG_VARS:
  412. _CONFIG_VARS['srcdir'] = _PROJECT_BASE
  413. else:
  414. _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir'])
  415. # Convert srcdir into an absolute path if it appears necessary.
  416. # Normally it is relative to the build directory. However, during
  417. # testing, for example, we might be running a non-installed python
  418. # from a different directory.
  419. if _PYTHON_BUILD and os.name == "posix":
  420. base = _PROJECT_BASE
  421. try:
  422. cwd = os.getcwd()
  423. except OSError:
  424. cwd = None
  425. if (not os.path.isabs(_CONFIG_VARS['srcdir']) and
  426. base != cwd):
  427. # srcdir is relative and we are not in the same directory
  428. # as the executable. Assume executable is in the build
  429. # directory and make srcdir absolute.
  430. srcdir = os.path.join(base, _CONFIG_VARS['srcdir'])
  431. _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir)
  432. if sys.platform == 'darwin':
  433. kernel_version = os.uname()[2] # Kernel version (8.4.3)
  434. major_version = int(kernel_version.split('.')[0])
  435. if major_version < 8:
  436. # On Mac OS X before 10.4, check if -arch and -isysroot
  437. # are in CFLAGS or LDFLAGS and remove them if they are.
  438. # This is needed when building extensions on a 10.3 system
  439. # using a universal build of python.
  440. for key in ('LDFLAGS', 'BASECFLAGS',
  441. # a number of derived variables. These need to be
  442. # patched up as well.
  443. 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
  444. flags = _CONFIG_VARS[key]
  445. flags = re.sub(r'-arch\s+\w+\s', ' ', flags)
  446. flags = re.sub('-isysroot [^ \t]*', ' ', flags)
  447. _CONFIG_VARS[key] = flags
  448. else:
  449. # Allow the user to override the architecture flags using
  450. # an environment variable.
  451. # NOTE: This name was introduced by Apple in OSX 10.5 and
  452. # is used by several scripting languages distributed with
  453. # that OS release.
  454. if 'ARCHFLAGS' in os.environ:
  455. arch = os.environ['ARCHFLAGS']
  456. for key in ('LDFLAGS', 'BASECFLAGS',
  457. # a number of derived variables. These need to be
  458. # patched up as well.
  459. 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
  460. flags = _CONFIG_VARS[key]
  461. flags = re.sub(r'-arch\s+\w+\s', ' ', flags)
  462. flags = flags + ' ' + arch
  463. _CONFIG_VARS[key] = flags
  464. # If we're on OSX 10.5 or later and the user tries to
  465. # compiles an extension using an SDK that is not present
  466. # on the current machine it is better to not use an SDK
  467. # than to fail.
  468. #
  469. # The major usecase for this is users using a Python.org
  470. # binary installer on OSX 10.6: that installer uses
  471. # the 10.4u SDK, but that SDK is not installed by default
  472. # when you install Xcode.
  473. #
  474. CFLAGS = _CONFIG_VARS.get('CFLAGS', '')
  475. m = re.search(r'-isysroot\s+(\S+)', CFLAGS)
  476. if m is not None:
  477. sdk = m.group(1)
  478. if not os.path.exists(sdk):
  479. for key in ('LDFLAGS', 'BASECFLAGS',
  480. # a number of derived variables. These need to be
  481. # patched up as well.
  482. 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
  483. flags = _CONFIG_VARS[key]
  484. flags = re.sub(r'-isysroot\s+\S+(\s|$)', ' ', flags)
  485. _CONFIG_VARS[key] = flags
  486. if args:
  487. vals = []
  488. for name in args:
  489. vals.append(_CONFIG_VARS.get(name))
  490. return vals
  491. else:
  492. return _CONFIG_VARS
  493. def get_config_var(name):
  494. """Return the value of a single variable using the dictionary returned by
  495. 'get_config_vars()'.
  496. Equivalent to get_config_vars().get(name)
  497. """
  498. return get_config_vars().get(name)
  499. def get_platform():
  500. """Return a string that identifies the current platform.
  501. This is used mainly to distinguish platform-specific build directories and
  502. platform-specific built distributions. Typically includes the OS name
  503. and version and the architecture (as supplied by 'os.uname()'),
  504. although the exact information included depends on the OS; eg. for IRIX
  505. the architecture isn't particularly important (IRIX only runs on SGI
  506. hardware), but for Linux the kernel version isn't particularly
  507. important.
  508. Examples of returned values:
  509. linux-i586
  510. linux-alpha (?)
  511. solaris-2.6-sun4u
  512. irix-5.3
  513. irix64-6.2
  514. Windows will return one of:
  515. win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
  516. win-ia64 (64bit Windows on Itanium)
  517. win32 (all others - specifically, sys.platform is returned)
  518. For other non-POSIX platforms, currently just returns 'sys.platform'.
  519. """
  520. if os.name == 'nt':
  521. # sniff sys.version for architecture.
  522. prefix = " bit ("
  523. i = sys.version.find(prefix)
  524. if i == -1:
  525. return sys.platform
  526. j = sys.version.find(")", i)
  527. look = sys.version[i+len(prefix):j].lower()
  528. if look == 'amd64':
  529. return 'win-amd64'
  530. if look == 'itanium':
  531. return 'win-ia64'
  532. return sys.platform
  533. if os.name != "posix" or not hasattr(os, 'uname'):
  534. # XXX what about the architecture? NT is Intel or Alpha,
  535. # Mac OS is M68k or PPC, etc.
  536. return sys.platform
  537. # Try to distinguish various flavours of Unix
  538. osname, host, release, version, machine = os.uname()
  539. # Convert the OS name to lowercase, remove '/' characters
  540. # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
  541. osname = osname.lower().replace('/', '')
  542. machine = machine.replace(' ', '_')
  543. machine = machine.replace('/', '-')
  544. if osname[:5] == "linux":
  545. # At least on Linux/Intel, 'machine' is the processor --
  546. # i386, etc.
  547. # XXX what about Alpha, SPARC, etc?
  548. return "%s-%s" % (osname, machine)
  549. elif osname[:5] == "sunos":
  550. if release[0] >= "5": # SunOS 5 == Solaris 2
  551. osname = "solaris"
  552. release = "%d.%s" % (int(release[0]) - 3, release[2:])
  553. # fall through to standard osname-release-machine representation
  554. elif osname[:4] == "irix": # could be "irix64"!
  555. return "%s-%s" % (osname, release)
  556. elif osname[:3] == "aix":
  557. return "%s-%s.%s" % (osname, version, release)
  558. elif osname[:6] == "cygwin":
  559. osname = "cygwin"
  560. rel_re = re.compile(r'[\d.]+')
  561. m = rel_re.match(release)
  562. if m:
  563. release = m.group()
  564. elif osname[:6] == "darwin":
  565. #
  566. # For our purposes, we'll assume that the system version from
  567. # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
  568. # to. This makes the compatibility story a bit more sane because the
  569. # machine is going to compile and link as if it were
  570. # MACOSX_DEPLOYMENT_TARGET.
  571. cfgvars = get_config_vars()
  572. macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
  573. if True:
  574. # Always calculate the release of the running machine,
  575. # needed to determine if we can build fat binaries or not.
  576. macrelease = macver
  577. # Get the system version. Reading this plist is a documented
  578. # way to get the system version (see the documentation for
  579. # the Gestalt Manager)
  580. try:
  581. f = open('/System/Library/CoreServices/SystemVersion.plist')
  582. except IOError:
  583. # We're on a plain darwin box, fall back to the default
  584. # behaviour.
  585. pass
  586. else:
  587. try:
  588. m = re.search(r'<key>ProductUserVisibleVersion</key>\s*'
  589. r'<string>(.*?)</string>', f.read())
  590. finally:
  591. f.close()
  592. if m is not None:
  593. macrelease = '.'.join(m.group(1).split('.')[:2])
  594. # else: fall back to the default behaviour
  595. if not macver:
  596. macver = macrelease
  597. if macver:
  598. release = macver
  599. osname = "macosx"
  600. if ((macrelease + '.') >= '10.4.' and
  601. '-arch' in get_config_vars().get('CFLAGS', '').strip()):
  602. # The universal build will build fat binaries, but not on
  603. # systems before 10.4
  604. #
  605. # Try to detect 4-way universal builds, those have machine-type
  606. # 'universal' instead of 'fat'.
  607. machine = 'fat'
  608. cflags = get_config_vars().get('CFLAGS')
  609. archs = re.findall(r'-arch\s+(\S+)', cflags)
  610. archs = tuple(sorted(set(archs)))
  611. if len(archs) == 1:
  612. machine = archs[0]
  613. elif archs == ('i386', 'ppc'):
  614. machine = 'fat'
  615. elif archs == ('i386', 'x86_64'):
  616. machine = 'intel'
  617. elif archs == ('i386', 'ppc', 'x86_64'):
  618. machine = 'fat3'
  619. elif archs == ('ppc64', 'x86_64'):
  620. machine = 'fat64'
  621. elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
  622. machine = 'universal'
  623. else:
  624. raise ValueError(
  625. "Don't know machine value for archs=%r" % (archs,))
  626. elif machine == 'i386':
  627. # On OSX the machine type returned by uname is always the
  628. # 32-bit variant, even if the executable architecture is
  629. # the 64-bit variant
  630. if sys.maxsize >= 2**32:
  631. machine = 'x86_64'
  632. elif machine in ('PowerPC', 'Power_Macintosh'):
  633. # Pick a sane name for the PPC architecture.
  634. # See 'i386' case
  635. if sys.maxsize >= 2**32:
  636. machine = 'ppc64'
  637. else:
  638. machine = 'ppc'
  639. return "%s-%s-%s" % (osname, release, machine)
  640. def get_python_version():
  641. return _PY_VERSION_SHORT
  642. def _print_dict(title, data):
  643. for index, (key, value) in enumerate(sorted(data.items())):
  644. if index == 0:
  645. print('%s: ' % (title))
  646. print('\t%s = "%s"' % (key, value))
  647. def _main():
  648. """Display all information sysconfig detains."""
  649. print('Platform: "%s"' % get_platform())
  650. print('Python version: "%s"' % get_python_version())
  651. print('Current installation scheme: "%s"' % _get_default_scheme())
  652. print()
  653. _print_dict('Paths', get_paths())
  654. print()
  655. _print_dict('Variables', get_config_vars())
  656. if __name__ == '__main__':
  657. _main()